package com.hyhy.hycloud.uaa.service;

import com.hyhy.hycloud.edu.rpc.api.ConfigurationServiceApi;
import com.hyhy.hycloud.edu.rpc.api.DictionaryServiceApi;
import com.hyhy.hycloud.uaa.exception.ExpiredVerificationCodeException;
import com.hyhy.hycloud.uaa.security.exception.BadAuthVerificationCodeException;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 验证码应用服务
 *
 * @author Xuegui Yuan
 * @date 2018-09-19
 */
@Service
public class VerificationCodeService implements SmsVerificationCodeByMobileFinder,
        VerificationCodeChecker {

    private static final int VERIFICATION_CODE_LEN = 4;
    private static final String APP_ID = "uaa";
    private static final String SMS_CODE_REDIS_KEY_PREFIX = "VCODE:SMS:";
    private static final String EMAIL_CODE_REDIS_KEY_PREFIX = "VCODE:EMAIL:";
    private static final String REGIST_SMS_TEMPLATE_ID = "REGIST_SMS_TEMPLATE_ID";
    private static final String LOGIN_SMS_TEMPLATE_ID = "LOGIN_SMS_TEMPLATE_ID";
    private static final String RESET_PASSWORD_SMS_TEMPLATE_ID = "RESET_PASSWORD_SMS_TEMPLATE_ID";
    private static final String CODE_EXPIRE = "CODE_EXPIRE";
    private static final String LOGIN = "login";
    private static final String UPDATE_LOGIN_PASSWORD = "update-login-password";
    private static final String REGIST = "regist";


    @Autowired
    RedisTemplate<String, String> verificationCodeRedisTemplate;

    @Autowired
    DictionaryServiceApi dictionaryServiceApi;
    @Autowired
    ConfigurationServiceApi configurationServiceApi;

    @Value("${uaa.verification-code.sms-template-id}")
    String verificationSmsTemplateId;

    private String getRedisSmsVerificationCodeKey(String bizCode, String mobile) {
        return SMS_CODE_REDIS_KEY_PREFIX + bizCode + ":" + mobile;
    }

    private String getRedisEmailVerificationCodeKey(String bizCode, String email) {
        return EMAIL_CODE_REDIS_KEY_PREFIX + bizCode + ":" + email;
    }

       @Override
    public String findSmsVerificationCode(String bizCode, String mobile) throws BadAuthVerificationCodeException {
        Assert.notNull(bizCode, "bizCode must not null");
        Assert.notNull(mobile, "mobile must not null");
        String code = verificationCodeRedisTemplate.opsForValue().get(getRedisSmsVerificationCodeKey(bizCode, mobile));
        if (StringUtils.isNoneBlank(code)) {
            return code;
        } else {
            throw new ExpiredVerificationCodeException();
        }
    }

    public void removeEmailVerificationCode(String bizCode, String email) {
        Assert.notNull(bizCode, "bizCode must not null");
        Assert.notNull(email, email);
        verificationCodeRedisTemplate.delete(getRedisEmailVerificationCodeKey(bizCode, email));
    }

    public void removeSmsVerificationCode(String bizCode, String mobile) {
        Assert.notNull(bizCode, "bizCode must not null");
        Assert.notNull(mobile, "mobile must not null");
        verificationCodeRedisTemplate.delete(getRedisSmsVerificationCodeKey(bizCode, mobile));
    }

    public String sendSmsVerificationCode(String appId, String bizCode, String mobile) {
        String codeTimeOut = configurationServiceApi.getConfigValueByKey(CODE_EXPIRE);
        String code = RandomStringUtils.randomNumeric(VERIFICATION_CODE_LEN);
        RestTemplate restTemplate = new RestTemplate();
        String templateId = "";
        if (LOGIN.equals(bizCode)) {
            templateId = configurationServiceApi.getConfigValueByKey(LOGIN_SMS_TEMPLATE_ID);
        } else if (UPDATE_LOGIN_PASSWORD.equals(bizCode)) {
            templateId = configurationServiceApi.getConfigValueByKey(RESET_PASSWORD_SMS_TEMPLATE_ID);
        } else if (REGIST.equals(bizCode)) {
            templateId = configurationServiceApi.getConfigValueByKey(REGIST_SMS_TEMPLATE_ID);
        }
        HttpHeaders headers = new HttpHeaders();
        headers.add("X-APP-ID", appId);
        headers.setContentType(MediaType.APPLICATION_JSON);
        Map<String, Object> map = new HashMap<String, Object>(3);
        map.put("mobile", mobile);
        map.put("templateId", templateId);
        String[] params = new String[2];
        params[0] = code;
        params[1] = codeTimeOut;
        map.put("params", params);
        HttpEntity<Map<String, Object>> request = new HttpEntity<Map<String, Object>>(map, headers);
        String url = "https://api.huiyihuiying.com/v3.1/sms/send-sms";
        ResponseEntity<String> entity = restTemplate.postForEntity(url, request, String.class);
        String key = getRedisSmsVerificationCodeKey(bizCode, mobile);
        verificationCodeRedisTemplate.opsForValue().set(key, code, Long.valueOf(codeTimeOut), TimeUnit.MINUTES);
        return code;
    }

    public String sendEmailVerificationCode(String appId, String bizCode, String email) {
        return null;
    }

    @Override
    public boolean checkSmsVerificationCode(String bizCode, String mobile, String code, boolean removeAfterSuccess) {
        if (StringUtils.isEmpty(bizCode) || StringUtils.isEmpty(mobile) || StringUtils.isEmpty(code)) {
            return false;
        }
        try {
            String verifyCode =
                    this.findSmsVerificationCode(bizCode, mobile);
            if (verifyCode.equals(code)) {
                this.removeSmsVerificationCode(bizCode, mobile);
                return true;
            }
            return false;
        } catch (BadAuthVerificationCodeException e) {
            return false;
        }
    }

    @Override
    public boolean checkSmsVerificationCode(String bizCode, String mobile, String code) {
        return checkSmsVerificationCode(bizCode, mobile, code, true);
    }

 }
